package com.zf.zffencheng.service.impl;

import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;
import com.zf.zffencheng.exception.Error_;
import com.zf.zffencheng.exception.ResultException;
import com.zf.zffencheng.model.Result;
import com.zf.zffencheng.service.SmsService;
import lombok.extern.log4j.Log4j2;
import org.apache.http.client.utils.DateUtils;
import org.joda.time.DateTimeUtils;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.IntegerCodec;
import org.redisson.client.codec.StringCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * ClassName: SmsService <br/>
 * Description:  <br/>
 * date: 2021/5/11 9:40<br/>
 *
 * @author william <br/>
 */
@Service
@Log4j2
public class SmsServiceImpl implements SmsService {
    private final RedissonClient redissonClient;

    @Autowired
    public SmsServiceImpl(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    /**
     * 校验手机号
     *
     * @param mobile
     * @param code
     */
    @Override
    public void verifyCode(String mobile, String code) {
        RBucket<String> bucket = redissonClient.getBucket(SMS_BUCKET.concat(":").concat(mobile), StringCodec.INSTANCE);
        //验证码不存在 验证码错误
        if(!bucket.isExists()){
            throw new ResultException(Error_.VERIFICATION_CODE_ERROR);
        }
        //缓存中的验证码
        String verifyCode = bucket.get();
        if(!code.equals(verifyCode)) {
            throw new ResultException(Error_.VERIFICATION_CODE_ERROR);
        }
        //验证通过后删除
        bucket.delete();
    }

    /**
     * 发送短信
     *
     * @param mobile
     * @param code
     * @return
     */
    @Override
    public Result send(String mobile, String code) throws Exception {
        //分控短信
        String yyyyMMdd = DateUtils.formatDate(new Date(), "yyyyMMdd");
        String dateBucket = SMS_RICK_CONTROL_BUCKET.concat(":").concat(mobile).concat("_date_").concat(yyyyMMdd);
        RAtomicLong smsRickControl = redissonClient.getAtomicLong(dateBucket);
        long l = smsRickControl.get();
        log.info("当前手机：{} ,  当日已发送条数:{},  分控上线条数：{}", mobile, l, SMS_RICK_CONTROL);
        //风控上限
        if(l > SMS_RICK_CONTROL){
            throw new ResultException(Error_.SMS_UPPER_LIMIT);
        }
        //AccessKey ID
        //AccessKey Secret
        //domain
        //获取AccessKey ID
        Client client = createClient();
        SendSmsRequest sendSmsRequest = new SendSmsRequest();
        String param = "{\"code\":\"%s\"}";
        sendSmsRequest
                //手机号
                .setPhoneNumbers(mobile)
                //签名
                .setSignName(ALI_SMS_SIGN_NAME)
                //模板
                .setTemplateCode(ALI_SMS_TEMPLATE)
                .setTemplateParam(String.format(param, code));
        // 复制代码运行请自行打印 API 的返回值
        SendSmsResponse response = client.sendSms(sendSmsRequest);
        String message = response.getBody().getMessage();
        String resCode = response.getBody().code;
        log.info("发送消息:{} code:{}", message, resCode);
        if("OK".equals(resCode)){
            log.info("当前手机：{}, 验证码：{}", mobile, code);
            //短信消息
            RBucket<String> bucket = redissonClient.getBucket(SMS_BUCKET.concat(":").concat(mobile), StringCodec.INSTANCE);
            bucket.set(code, SMS_EXPIRE, TimeUnit.MINUTES);
            //分控
            smsRickControl.getAndIncrement();
            smsRickControl.expire(SMS_RICK_CONTROL_TIME, TimeUnit.HOURS);
            return Result.ok();
        }else{
            if("isv.BUSINESS_LIMIT_CONTROL".equals(resCode)){
                //限流
                return Result.error(Error_.SMS_CANNOT_SEND.getCode(), "短消息发送失败, 短信消息频繁");
            }
            return Result.error(Error_.SMS_CANNOT_SEND);
        }
    }

    private Client createClient() throws Exception {
        Config config = new Config()
                // 您的AccessKey ID
                .setAccessKeyId(ALI_ACCESS_ID)
                // 您的AccessKey Secret
                .setAccessKeySecret(ALI_ACCESS_SECRET);
        // 访问的域名
        config.endpoint = ALI_SMS_DOMAIN;
        return new Client(config);
    }
}
